"""
File type detection and validation utilities
"""
import mimetypes
import os
from pathlib import Path
from typing import Optional, Dict, List, Union
import logging

from ..parsers.base import FileType

logger = logging.getLogger(__name__)


class FileDetector:
    """
    File type detection utility using MIME types and file headers
    """
    
    # MIME type mappings to our FileType enum
    MIME_TO_FILETYPE = {
        # PDF files
        "application/pdf": FileType.PDF,
        
        # Word documents
        "application/msword": FileType.WORD,
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document": FileType.WORD,
        
        # Excel files
        "application/vnd.ms-excel": FileType.EXCEL,
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": FileType.EXCEL,
        
        # Images
        "image/jpeg": FileType.IMAGE,
        "image/jpg": FileType.IMAGE,
        "image/png": FileType.IMAGE,
        "image/gif": FileType.IMAGE,
        "image/bmp": FileType.IMAGE,
        "image/tiff": FileType.IMAGE,
        "image/webp": FileType.IMAGE,
        
        # Text files
        "text/plain": FileType.PLAIN_TEXT,
        "text/markdown": FileType.MARKDOWN,
        "text/x-markdown": FileType.MARKDOWN,
    }
    
    # File extension mappings as fallback
    EXTENSION_TO_FILETYPE = {
        # PDF
        ".pdf": FileType.PDF,
        
        # Word
        ".doc": FileType.WORD,
        ".docx": FileType.WORD,
        
        # Excel
        ".xls": FileType.EXCEL,
        ".xlsx": FileType.EXCEL,
        ".xlsm": FileType.EXCEL,
        
        # Markdown
        ".md": FileType.MARKDOWN,
        ".markdown": FileType.MARKDOWN,
        ".mdown": FileType.MARKDOWN,
        ".mkd": FileType.MARKDOWN,
        
        # Images
        ".jpg": FileType.IMAGE,
        ".jpeg": FileType.IMAGE,
        ".png": FileType.IMAGE,
        ".gif": FileType.IMAGE,
        ".bmp": FileType.IMAGE,
        ".tiff": FileType.IMAGE,
        ".tif": FileType.IMAGE,
        ".webp": FileType.IMAGE,
        
        # Text
        ".txt": FileType.PLAIN_TEXT,
    }
    
    # File signature (magic numbers) for validation
    FILE_SIGNATURES = {
        FileType.PDF: [
            b"%PDF-",  # PDF signature
        ],
        FileType.IMAGE: [
            b"\xFF\xD8\xFF",  # JPEG
            b"\x89PNG\r\n\x1A\n",  # PNG
            b"GIF87a",  # GIF87a
            b"GIF89a",  # GIF89a
            b"BM",  # BMP
            b"II*\x00",  # TIFF little endian
            b"MM\x00*",  # TIFF big endian
            b"RIFF",  # WEBP (check for WEBP in bytes 8-11)
        ],
        FileType.WORD: [
            b"PK\x03\x04",  # ZIP-based (DOCX)
            b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",  # OLE2 (DOC)
        ],
        FileType.EXCEL: [
            b"PK\x03\x04",  # ZIP-based (XLSX)
            b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",  # OLE2 (XLS)
        ]
    }
    
    # Maximum file sizes for different types (in bytes)
    MAX_FILE_SIZES = {
        FileType.PDF: 100 * 1024 * 1024,  # 100MB
        FileType.WORD: 50 * 1024 * 1024,   # 50MB
        FileType.EXCEL: 50 * 1024 * 1024,  # 50MB
        FileType.MARKDOWN: 10 * 1024 * 1024,  # 10MB
        FileType.IMAGE: 20 * 1024 * 1024,   # 20MB
        FileType.PLAIN_TEXT: 10 * 1024 * 1024,  # 10MB
    }
    
    def __init__(self):
        # Initialize mimetypes
        mimetypes.init()
    
    def detect_file_type(self, file_path: Union[str, Path]) -> FileType:
        """
        Detect file type using multiple methods
        
        Args:
            file_path: Path to the file
            
        Returns:
            Detected FileType
        """
        file_path = Path(file_path)
        
        if not file_path.exists() or not file_path.is_file():
            logger.warning(f"File does not exist or is not a file: {file_path}")
            return FileType.UNKNOWN
        
        # Method 1: Try MIME type detection
        try:
            file_type = self._detect_by_mime_type(file_path)
            if file_type != FileType.UNKNOWN:
                logger.debug(f"Detected file type by MIME: {file_type}")
                return file_type
        except Exception as e:
            logger.debug(f"MIME type detection failed: {e}")
        
        # Method 2: Try file signature detection
        try:
            file_type = self._detect_by_signature(file_path)
            if file_type != FileType.UNKNOWN:
                logger.debug(f"Detected file type by signature: {file_type}")
                return file_type
        except Exception as e:
            logger.debug(f"File signature detection failed: {e}")
        
        # Method 3: Fall back to extension
        try:
            file_type = self._detect_by_extension(file_path)
            if file_type != FileType.UNKNOWN:
                logger.debug(f"Detected file type by extension: {file_type}")
                return file_type
        except Exception as e:
            logger.debug(f"Extension detection failed: {e}")
        
        logger.warning(f"Could not detect file type for: {file_path}")
        return FileType.UNKNOWN
    
    def _detect_by_mime_type(self, file_path: Path) -> FileType:
        """Detect file type using MIME type"""
        mime_type, _ = mimetypes.guess_type(str(file_path))
        
        if mime_type:
            return self.MIME_TO_FILETYPE.get(mime_type, FileType.UNKNOWN)
        
        return FileType.UNKNOWN
    
    def _detect_by_signature(self, file_path: Path) -> FileType:
        """Detect file type using file signature (magic numbers)"""
        try:
            with open(file_path, "rb") as f:
                header = f.read(16)  # Read first 16 bytes
            
            for file_type, signatures in self.FILE_SIGNATURES.items():
                for signature in signatures:
                    if header.startswith(signature):
                        return file_type
                    
                    # Special case for WEBP
                    if signature == b"RIFF" and len(header) >= 12:
                        if header.startswith(b"RIFF") and header[8:12] == b"WEBP":
                            return FileType.IMAGE
            
            return FileType.UNKNOWN
            
        except Exception as e:
            logger.error(f"Error reading file signature: {e}")
            return FileType.UNKNOWN
    
    def _detect_by_extension(self, file_path: Path) -> FileType:
        """Detect file type using file extension"""
        extension = file_path.suffix.lower()
        return self.EXTENSION_TO_FILETYPE.get(extension, FileType.UNKNOWN)
    
    def validate_file_size(self, file_path: Union[str, Path], file_type: FileType) -> bool:
        """
        Validate file size against type-specific limits
        
        Args:
            file_path: Path to the file
            file_type: Detected file type
            
        Returns:
            True if file size is within limits
        """
        file_path = Path(file_path)
        
        try:
            file_size = file_path.stat().st_size
            max_size = self.MAX_FILE_SIZES.get(file_type, 100 * 1024 * 1024)  # Default 100MB
            
            if file_size > max_size:
                logger.warning(
                    f"File size {file_size} bytes exceeds limit {max_size} bytes for type {file_type}"
                )
                return False
            
            return True
            
        except Exception as e:
            logger.error(f"Error checking file size: {e}")
            return False
    
    def get_supported_file_types(self) -> List[FileType]:
        """Get list of supported file types"""
        return list(set(self.MIME_TO_FILETYPE.values()) | set(self.EXTENSION_TO_FILETYPE.values()))
    
    def get_supported_extensions(self) -> List[str]:
        """Get list of supported file extensions"""
        return list(self.EXTENSION_TO_FILETYPE.keys())
    
    def get_supported_mime_types(self) -> List[str]:
        """Get list of supported MIME types"""
        return list(self.MIME_TO_FILETYPE.keys())
    
    def is_supported_file(self, file_path: Union[str, Path]) -> bool:
        """
        Check if file is supported for parsing
        
        Args:
            file_path: Path to the file
            
        Returns:
            True if file type is supported
        """
        file_type = self.detect_file_type(file_path)
        return file_type != FileType.UNKNOWN
    
    def get_file_info(self, file_path: Union[str, Path]) -> Dict[str, Union[str, int, bool]]:
        """
        Get comprehensive file information
        
        Args:
            file_path: Path to the file
            
        Returns:
            Dictionary with file information
        """
        file_path = Path(file_path)
        
        file_type = self.detect_file_type(file_path)
        is_supported = file_type != FileType.UNKNOWN
        size_valid = self.validate_file_size(file_path, file_type) if is_supported else False
        
        info = {
            "file_path": str(file_path),
            "file_name": file_path.name,
            "file_extension": file_path.suffix.lower(),
            "detected_type": file_type.value,
            "is_supported": is_supported,
            "size_valid": size_valid,
        }
        
        try:
            stat = file_path.stat()
            info.update({
                "file_size": stat.st_size,
                "created_time": stat.st_ctime,
                "modified_time": stat.st_mtime,
            })
            
            mime_type, _ = mimetypes.guess_type(str(file_path))
            if mime_type:
                info["mime_type"] = mime_type
                
        except Exception as e:
            logger.error(f"Error getting file info: {e}")
            info["error"] = str(e)
        
        return info


# Global file detector instance
file_detector = FileDetector()